package com.pi.pro.xcmg.am.rf.fac.service;




import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.collect.HashMultimap;
import com.pi.common.CodesConstants;
import com.pi.common.utils.MathUtils;
import com.pi.common.utils.StringUtils;
import com.pi.common.utils.TextUtils;
import com.pi.framework.core.util.DateUtils;
import com.pi.framework.core.util.SecurityUtils;
import com.pi.framework.dto.ReturnArrangeDataItemDto;
import com.pi.framework.dto.api.ReturnArrangeDataPack;
import com.pi.framework.dto.api.ReturnMessageInfoData;
import com.pi.pro.xcmg.am.common.XcmgAmConstants;
import com.pi.pro.xcmg.am.was.fac.calculator.PalletizeDataStorageBuilder;
import com.pi.wms.common.WmsConstants;
import com.pi.wms.config.WmsClientConfig;
import com.pi.wms.dto.act.*;
import com.pi.wms.dto.base.LocationLineDto;
import com.pi.wms.entity.*;
import com.pi.wms.fac.LocationResolver;
import com.pi.wms.service.*;
import org.apache.commons.collections.map.HashedMap;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


/**
 *
 */
@Service("XCMGRFCUSTOMWORKSERVICE")
public class XcmgAmRfCustomWorkService {


    @Autowired
    private CustomerService customerService;

    @Autowired
    private MaterialService materialService;

    @Autowired
    private LogisticsSeqService seqService;

    @Autowired
    private LocationService locationService;

    @Autowired
    private ZoneService zoneService;

    @Autowired
    protected LogisticsCodeListService codeListService;

    @Autowired
    private AsnService asnService;

    @Autowired
    private AsnDetailsService asnDetailsService;

    @Autowired
    private InventoryDetailsService inventoryService;

    @Autowired
    private InventoryStorageSeqService inventorySeqService;

    @Autowired
    private StorageService storageService;

    @Autowired
    private InventoryStorageSeqService storageSeqService;

    @Autowired
    private SoService soService;

    @Autowired
    private PalletizeService palletizeService;

    @Autowired
    private ReceiveService receiveService;

    @Autowired
    private AllocationService allocationService;

    @Autowired
    private TaskService taskService;

    @Autowired
    private LocationResolver locationResolver;

    @Autowired
    private PalletizeDataStorageBuilder palletizeDataStorageBuilder;

    @Autowired
    private WmsClientConfig clientConfig;


// ---------------------------------------------------------------------------------------------
// ----
// ---------------------------------------------------------------------------------------------


    private Cache<Long, TwmBasMaterial> materialCache = CacheBuilder.newBuilder().expireAfterWrite(20, TimeUnit.MINUTES).build();
    private  Cache<Long, TwmBasLocation> locationCache= CacheBuilder.newBuilder().expireAfterWrite(30, TimeUnit.MINUTES).build();




// ---------------------------------------------------------------------------------------------
// ----  常量定义  ------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------------

    public XcmgAmRfCustomWorkService() {
    }



// ---------------------------------------------------------------------------------------------
// ----  配置  相关---------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------------


// ---------------------------------------------------------------------------------------------
// ----  主数据  相关---------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------------



// ---------------------------------------------------------------------------------------------
// --------  码盘    ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------------
    //新增
    public String palletizeCreate(String batchNumber, String containNumber, String traceNumber, String materialCode, String documentNumber, String locationCode,
                                  String workMode, String worker) {
        String m = "";
        if (StringUtils.isNullOrBlank(containNumber)){
            m="请指定托盘码.";
            return m;
        }
        if (StringUtils.isNullOrBlank(traceNumber)){
            m="请指定箱码.";
            return m;
        }
        if (StringUtils.isNullOrBlank(locationCode)){
            locationCode=XcmgAmConstants.LOCATION_CODE_PA0101;

        }
        containNumber=containNumber.trim();
        traceNumber=traceNumber.trim();

        List<TwaInventoryStorageSeqList> inventSeqDatas = null;
        TwaInventoryStorageSeqList inventSeqData=null;
        TwtActPalletizeList palletize=null;
        List<TwtActPalletizeList> palletizes = null;
        TwmBasMaterial material=null;
        TwaDocAsnHeader header=null;
        TwaDocAsnDetails line=null;
        List<TwaDocAsnDetails> lines=null;

        try{
            palletizes=this.palletizeService.findByTraceNumber(traceNumber);
            if ((palletizes!=null)&&(palletizes.size()>0)){
                m="料箱已经码盘,不能重复码盘.箱码:"+traceNumber;
                return m;
            }
            //1. 装箱数据
            inventSeqDatas = this.inventorySeqService.findByTraceNumber(traceNumber);
            if ((inventSeqDatas==null)||(inventSeqDatas.size()==0)){
                m="找不到箱码数据,请确认数据已经导入WMS.箱码:"+traceNumber;
                return m;
            }
            inventSeqData=inventSeqDatas.get(0);

            //物料核对
            if (!StringUtils.isNullOrBlank(materialCode)){
                material = this.materialService.lookup(inventSeqData.getMaterialId());
                if (material==null){
                    m="找不到物料主数据,请确认是否已删除.物料ID:"+String.valueOf(inventSeqData.getMaterialId());
                    return m;
                }
                if (!material.getCode().equalsIgnoreCase(materialCode.trim())){
                    m="当前扫描物料与接口传入物料不一致,请核对.码盘物料:"+materialCode+",接口物料:"+material.getCode();
                    return m;
                }
            }
            //单证核对
            if (!StringUtils.isNullOrBlank(inventSeqData.getReceiveDocNumber())){
                header=this.asnService.findByDocumentNumber(inventSeqData.getReceiveDocNumber().trim());
                if (header!=null){
                    if (!StringUtils.isNullOrBlank(inventSeqData.getReceiveDocLinenumber())){
                        line=this.asnDetailsService.findByDocumentLine(header.getId(), inventSeqData.getReceiveDocLinenumber().trim());
                    }else {
                        lines=this.asnDetailsService.findByMaterial(header.getId(), inventSeqData.getMaterialId());
                        if ((lines!=null) && (lines.size()>0)){
                            line=lines.get(0);
                        }
                    }
                }
            }

            //2. 生成码盘数据
            palletize=this.createPalletizeData(batchNumber, containNumber, inventSeqData, inventSeqDatas.size(), locationCode, header, line, workMode, worker);
            if (palletize!=null){
                this.palletizeService.save(palletize);
            }

            //3. 更新装箱信息
            this.updateStorageSequenceData(inventSeqDatas, containNumber, worker);

        }catch (Exception e){
            m="新增装箱异常.箱码:"+traceNumber+",托盘码:"+containNumber+",异常:"+e.getMessage();
            e.printStackTrace();
        }
        return m;
    }

    //删除
    public String palletizeDelete(Long palletizeId, String containNumber, String traceNumber, String worker) {
        String m = "";

        //1. 删除码盘数据
        PalletizeActionDto actionDto=new PalletizeActionDto();
        actionDto.setWorker(worker);
        m=this.palletizeService.cancel(palletizeId, containNumber, traceNumber, actionDto);

        //2. 更新装箱信息
        this.updateStorageSequenceData(traceNumber, containNumber, worker);

        return m;
    }

    //清除
    public String palletizeClean(String containNumber, String workmode, String worker) {
        String m = "";

        List<TwaInventoryStorageSeqList> datas=null;
        PalletizeActionDto actionDto=new PalletizeActionDto();
        try{
            //1. 查出装箱数据
            datas=this.inventorySeqService.findByContainNumber(containNumber);

            //2. 清除码盘数据
            actionDto=new PalletizeActionDto();
            actionDto.setWorker(worker);
            m=this.palletizeService.clean(containNumber, actionDto);
            if (!StringUtils.isNullOrBlank(m)){
                return m;
            }

            //3. 清除装箱数据
            if ((datas!=null) && (datas.size()>0)){
                m = this.updateStorageSequenceData(datas, null, worker);
            }
        }catch (Exception e){
            m="更新装箱清单出错.托盘码:"+containNumber+",异常:"+e.getMessage();
            e.printStackTrace();
        }
        return m;
    }

    //创建码盘数据
    private TwtActPalletizeList createPalletizeData(String batchnum, String containnum, TwaInventoryStorageSeqList seqdata, int count, String locationcode,
                                                    TwaDocAsnHeader header, TwaDocAsnDetails line,
                                                    String workMode, String worker){
        TwtActPalletizeList palletize=null;
        if (StringUtils.isNullOrBlank(containnum)){
            return palletize;
        }
        if (seqdata==null){
            return palletize;
        }
        if (count<=0){
            return palletize;
        }
        if (StringUtils.isNullOrBlank(locationcode)){
            locationcode= XcmgAmConstants.LOCATION_CODE_PA0101;
        }
        locationcode=locationcode.trim();

        TwmBasMaterial material=null;
        LocationLineDto loc=null;
        try{
            material=this.materialService.findById(seqdata.getMaterialId());
            if (material==null){
                return palletize;
            }
            loc=this.locationResolver.lookup(seqdata.getDivisionId(), locationcode);
            if (loc==null){
                return palletize;
            }
            palletize=new TwtActPalletizeList();
            palletize.setGlobalClientId(seqdata.getGlobalClientId());
            palletize.setDivisionId(seqdata.getDivisionId());
            palletize.setCustomerId(seqdata.getCustomerId());
            palletize.setBatchNumber(batchnum);
            palletize.setTransId(null);
            palletize.setLineSeq(null); //
            palletize.setWorker(worker);
            palletize.setWorkingType(null);
            palletize.setWorkMode(workMode);
            palletize.setContainNumber(containnum);
            palletize.setTraceNumber(seqdata.getTraceNumber());
            palletize.setLineStatus(WmsConstants.TASK_STATUS_CREATE);
            //
            palletize.setDocumentId(null);
            palletize.setDocumentDetailsId(null);
            palletize.setDocNumber(seqdata.getReceiveDocNumber());
            palletize.setDocLinenumber(seqdata.getReceiveDocLinenumber());
            palletize.setDocType(null);
            if (header!=null){
                palletize.setDocumentId(header.getId());
                palletize.setDocNumber(header.getDocumentNumber());
                palletize.setDocType(header.getType());
                if (line!=null){
                    palletize.setDocumentDetailsId(line.getId());
                    palletize.setDocLinenumber(line.getLineNumber());
                }
            }

            //
            palletize.setMaterialId(seqdata.getMaterialId());
            palletize.setMaterialCode(material.getCode());
            palletize.setQty(new BigDecimal(count));
            palletize.setQtyEach(palletize.getQty());
            palletize.setQtyCaseCapacity(palletize.getQtyEach());
            palletize.setQtyPalletCapacity(palletize.getQtyCaseCapacity());
            palletize.setPackId(material.getPackId());
            palletize.setPackCode(null); //
            palletize.setPackType(CodesConstants.UOM_EACH);
            palletize.setUomCode(CodesConstants.UOM_EACH);

            palletize.setLotNumber(seqdata.getLotNumber());
            palletize.setLocationId(loc.getLocationId());
            palletize.setLocationCode(locationcode);
            palletize.setPlantoLocationId(null);
            palletize.setPlantoLocationCode(null);

            palletize.setSupplierCode(null);
            palletize.setProductionDate(null);
            palletize.setQcStatus(seqdata.getQualityStatus());

            palletize.setPrice(null);
            palletize.setCubic(null);
            palletize.setGrossweight(null);
            palletize.setNetweight(null);
            palletize.setLen(null);
            palletize.setWidth(null);
            palletize.setHeight(null);

            palletize.setRefNumber(null);
            palletize.setLotattr01(null);
            palletize.setLotattr02(null);
            palletize.setLotattr03(null);
            palletize.setLotattr04(null);
            palletize.setLotattr05(seqdata.getLotNumber());
            palletize.setLotattr06(null);
            palletize.setLotattr07(null);
            palletize.setLotattr08(null);
            palletize.setLotattr09(null);
            palletize.setLotattr10(null);
            palletize.setLotattr11(null);
            palletize.setLotattr12(null);
            palletize.setLotattr13(null);
            palletize.setLotattr14(null);
            palletize.setLotattr15(null);
            palletize.setLotattr16(null);

            palletize.setUdf01(seqdata.getUdf01());
            palletize.setUdf02(seqdata.getUdf02());
            palletize.setUdf03(seqdata.getUdf03());
            palletize.setUdf04(seqdata.getUdf04());
            palletize.setUdf05(seqdata.getUdf05());
            palletize.setUdf06(seqdata.getUdf06());
            palletize.setUdf07(seqdata.getUdf07());
            palletize.setUdf08(seqdata.getUdf08());
            palletize.setUdf09(seqdata.getUdf09());
            palletize.setUdf10(seqdata.getUdf10());

            palletize.setCheckedValue(null);
            palletize.setCheckedCode(null);
            palletize.setCheckedMsg(null);
            palletize.setEdiSendTime(null);
            palletize.setEdiSendStatus(CodesConstants.COMMON_STATUS_CREATED);
            palletize.setEdiReceiveTime(null);
            palletize.setEdiReceiveStatus(null);
            palletize.setEdiReceiveMsg(null);

            palletize.setNotes(null);
            palletize.setCreatedBy(worker);
            palletize.setCreatedDate(new Date());
            palletize.setLastModifiedBy(palletize.getCreatedBy());
            palletize.setLastModifiedDate(palletize.getCreatedDate());

            this.palletizeService.save(palletize);
        }catch (Exception e){
            e.getMessage();
        }
        return palletize;
    }

    //更新装箱数据
    private String updateStorageSequenceData(String traceNumber, String containNumber, String worker){
        String m="";

        List<TwaInventoryStorageSeqList> datas=null;
        try{
            datas=this.inventorySeqService.findByTraceNumber(traceNumber);
            m = this.updateStorageSequenceData(datas, containNumber, worker);
        }catch (Exception e){
            m="更新装箱清单出错.托盘码:"+containNumber+",异常:"+e.getMessage();
            e.printStackTrace();
        }
        return m;
    }

    //更新装箱数据
    private String updateStorageSequenceData(List<TwaInventoryStorageSeqList> inventorySeqDatas, String containNumber, String worker){
        String m="";

        if ((inventorySeqDatas==null)||(inventorySeqDatas.size()==0)){
            return m;
        }
        if (StringUtils.isNullOrBlank(containNumber)){
            containNumber=null;
        }
        if (StringUtils.isNullOrBlank(worker)){
            worker=SecurityUtils.getLoginUsername();
        }
        List<String> seqnums=new ArrayList<>();
        Date curdate = new Date();
        try{
            for (TwaInventoryStorageSeqList d:inventorySeqDatas){
                if (d==null){
                    continue;
                }
                if (CodesConstants.COMMON_STATUS_CLOSED.equalsIgnoreCase(d.getStatus())){
                    continue;
                }
                if (CodesConstants.COMMON_STATUS_CANCELLED.equalsIgnoreCase(d.getStatus())){
                    continue;
                }
                seqnums.add(d.getSeqNumber());
                /**
                d.setContainNumber(containNumber);
                d.setLastModifiedDate(curdate);
                d.setLastModifiedBy(worker);
                this.inventorySeqService.save(d);
                **/
            }
            if ((seqnums==null)||(seqnums.size()==0)){
                return m;
            }
            this.inventorySeqService.palletized(seqnums, containNumber, worker);
        }catch (Exception e){
            m="更新装箱清单出错.托盘码:"+containNumber+",异常:"+e.getMessage();
            e.printStackTrace();
        }
        return m;
    }




// ---------------------------------------------------------------------------------------------
// ----  收货  ----------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------------
    public String receive(String customerCode, String materialCode, BigDecimal quantity, String uomCode, String lotNumber,
                          String containNumber, String traceNumber, String locationCode,
                          String documentNumber, String docLineNumber,
                          String productDate, String expireDate,
                          String workMode){
        String m = "";


        //container-number
        if  ((workMode!=null) && (workMode.contains(WmsConstants.RECEIVE_MODE_MILK_RUN))){
            if (StringUtils.isNullOrBlank(containNumber)){
                containNumber=this.seqService.next(WmsConstants.SEQUENCE_NAME_ACT_RECEIVE);
            }
        }

        if  ((workMode!=null) && (!workMode.contains("PALLETIZE"))){
            if ((StringUtils.isNullOrBlank(materialCode))){
                m = "请指定收货物料";
                return m;
            }
            if ((StringUtils.isNullOrBlank(materialCode))){
                 m = "请指定收货物料";
                return m;
            }
            if (!MathUtils.validQuantity(quantity)){
                m = "请指定有效的收货数量";
                return m;
            }
        }

        if (StringUtils.isNullOrBlank(containNumber)){
            containNumber=CodesConstants.COMMON_WILDCARD;
        }
        containNumber=containNumber.trim();
        Pattern pattern = Pattern.compile(WmsConstants.TRACE_NUMBER_EXP_PATTERN);
        Matcher matcher = pattern.matcher(containNumber);
        if (!matcher.matches()){
            m="请扫描有效的托盘码.托盘码:"+containNumber;
            return m;
        }
        //
        m = this.working(containNumber, workMode);
        if (!StringUtils.isNullOrBlank(m)){
            return m;
        }

        //
        String batchnum=TextUtils.genBatchNumber();
        List<TwtActPalletizeList> pals=null;
        try{
            //TODO:HU/202504
            /**
            if ((workMode!=null) && (workMode.contains(ShenzhenGasQiuyulingConstants.RECEIVE_MODE_FOLLOW_PALLETIZE))
                    && (!CodesConstants.COMMON_WILDCARD.equalsIgnoreCase(containNumber))){
                pals=this.palletizeService.findByContainNumber(containNumber);
            }
             **/
            if ((pals==null) || (pals.size()==0)){
                m = this.bulkReceive(batchnum, customerCode, materialCode, quantity, uomCode, lotNumber, containNumber, traceNumber, locationCode, documentNumber, docLineNumber, productDate, expireDate, workMode);
            }else {
                m = this.palletizeReceive(batchnum,  pals, customerCode, materialCode, lotNumber, containNumber, locationCode, documentNumber, docLineNumber, productDate, workMode);
            }
        }catch (Exception e){
            m="收货出错.错误:"+e.getMessage();
            e.printStackTrace();
        }
        return m;
    }

    private String bulkReceive(String batchNumber, String customerCode, String materialCode, BigDecimal quantity, String uomCode, String lotNumber,
                          String containNumber, String traceNumber, String locationCode,
                          String documentNumber, String documentLineNumber,
                          String productDate, String expireDate,
                          String workMode){
        //

        TwmBasMaterial material=this.materialService.lookup(customerCode, materialCode);
        return receiveAction(batchNumber, material, quantity, uomCode, lotNumber, containNumber, traceNumber, locationCode, documentNumber, documentLineNumber, productDate, expireDate, workMode);
    }

    private String palletizeReceive(String batchNumber, List<TwtActPalletizeList> palletizes, String customerCode, String materialCode, String lotNumber,
                               String containNumber, String locationCode,
                               String documentNumber, String documentLineNumber, String productionDate,
                               String workMode){
        String m = "";
        if ((palletizes==null)||(palletizes.size()==0)){
            m="palletize is null";
            return m;
        }

        //
        Map<String, TwmBasMaterial> materials=new HashMap<>();
        TwmBasMaterial material=null;
        //check
        try{
            for (TwtActPalletizeList pal:palletizes){
                if (pal==null){
                    continue;
                }
                if ((!StringUtils.isNullOrBlank(containNumber))
                        && (!pal.getContainNumber().equalsIgnoreCase(containNumber))){
                    m="收货托盘与码盘托盘不一致.收货托盘:"+containNumber+",码盘托盘:"+pal.getContainNumber();
                    break;
                }
                if (!StringUtils.isNullOrBlank(materialCode)){
                    material=this.materialService.lookup(customerCode, materialCode.trim());
                    if (material!=null){
                        if (!pal.getMaterialId().equals(material.getId())){
                            m="收货物料与码盘物料不一致.收货物料:"+materialCode+",码盘物料:"+pal.getMaterialCode();
                            break;
                        }
                    }
                }
                //check document
                if ((!StringUtils.isNullOrBlank(documentNumber))
                    //&& (!StringUtils.isNullOrBlank(documentLineNumber))
                        ){
                    if (!documentNumber.trim().equalsIgnoreCase(pal.getDocNumber())){
                        m="收货单证与码盘单证不一致.收货单证:"+documentNumber+",码盘单证:"+pal.getDocNumber();
                        break;
                    }
                }
            }
        }catch (Exception e){
            m="收货校验出错:"+e.getMessage();
            e.printStackTrace();
        }

        //prepare
        if (lotNumber!=null){
            lotNumber = lotNumber.trim();
        }
        List<TwtActPalletizeList> pals=new ArrayList<>();
        try{
            for (TwtActPalletizeList pal:palletizes) {
                if (pal == null) {
                    continue;
                }
                if (!StringUtils.isNullOrBlank(lotNumber)){
                    if (!lotNumber.trim().equalsIgnoreCase(pal.getLotNumber())){
                        pal.setLotNumber(lotNumber);
                        pal.setLotattr05(pal.getLotNumber());
                        if (!StringUtils.isNullOrBlank(productionDate)){
                            pal.setProductionDate(productionDate.trim());
                        }
                        this.palletizeService.save(pal);
                        pal=this.palletizeService.findById(pal.getId());
                    }
                }
                pals.add(pal);
            }
        }catch (Exception e){
            e.printStackTrace();
        }

        //recive
        try{
            for (TwtActPalletizeList pal:pals) {
                if (pal == null) {
                    continue;
                }
                material=this.materialService.lookup(pal.getMaterialId());
                m = receiveAction(batchNumber, material, pal.getQty(), pal.getUomCode(), pal.getLotNumber(), pal.getContainNumber(), pal.getTraceNumber(), locationCode,
                        pal.getDocNumber(), pal.getDocLinenumber(), pal.getProductionDate(), null, workMode);
                if (!StringUtils.isNullOrBlank(m)){
                    break;
                }
                this.palletizeService.delete(pal);
            }
        }catch (Exception e){
            m="收货校验:"+e.getMessage();
            e.printStackTrace();
        }
        return m;
    }

    public String generateMoveinTask(String batchNumber, String containNumber, String fromLocationCode, TaskActionDto actionDto){
        String m="";
        if (StringUtils.isNullOrBlank(containNumber)){
            m="必须指定托盘码.";
            return m;
        }
        if (StringUtils.isNullOrBlank(fromLocationCode)){
            m="必须指定起始库位.";
            return m;
        }
        if (actionDto==null){
            actionDto=new TaskActionDto();
            actionDto.setWorker(SecurityUtils.getLoginUsername());
        }
        if (StringUtils.isNullOrBlank(actionDto.getTaskType())){
            actionDto.setTaskType(WmsConstants.TASK_TYPE_PUTAWAY);
        }
        containNumber=containNumber.trim();
        fromLocationCode=fromLocationCode.trim();
        LocationLineDto fmloc=null;
        List<TwtActTaskList> tasks=null;
        try{
            fmloc=this.locationResolver.lookup(fromLocationCode);
            if (fmloc==null){
                m="找不到库位主数据,不能生成任务.库位编码:"+fromLocationCode;
                return m;
            }
            if (WmsConstants.LOCATION_TYPE_BIN.equalsIgnoreCase(fmloc.getLocationType())){
                m="起始库位为库内库位,不能生成任务.库位编码:"+fromLocationCode;
                return m;
            }
            tasks=this.taskService.queryWorkingTasks(null);
            if ((tasks!=null)&&(tasks.size()>0)){
                for (TwtActTaskList t:tasks){
                    if (t==null){
                        continue;
                    }
                    //TODO:HU/202504
                    /**
                    if ((ShenzhenGasQiuyulingConstants.TASK_RELEASE_PA_MODE.equalsIgnoreCase(ShenzhenGasQiuyulingConstants.TASK_RELEASE_PA_MODE_LOC_ON_FIN))
                            && (fmloc.getLocationId().equals(t.getFromLocId()))){
                        m="当前库位已经生成上架任务.托盘码:"+t.getFromContainNumber();
                        return m;
                    }
                    **/
                    if (fmloc.getLocationId().equals(t.getToLocId())){
                        m="已经生成到当前库位的下架任务.任务号:"+t.getNumber()+",托盘码:"+t.getFromContainNumber();
                        return m;
                    }
                    if ((t.getPlantoLocId()!=null) && (fmloc.getLocationId().equals(t.getPlantoLocId()))){
                        m="已经生成到当前库位的下架任务.任务号:"+t.getNumber()+",托盘码:"+t.getFromContainNumber();
                        return m;
                    }
                }
            }
            m=this.storageService.moveinTask(batchNumber, containNumber, fromLocationCode, actionDto);

        }catch (Exception e){
            m="生成上架任异常.异常信息:"+e.getMessage();
            e.printStackTrace();
        }
        return m;
    }

    public String palletizeReceive(String documnetNumber, String containNumber, String locationCode, TaskActionDto actionDto){
        String m = "";
        if (StringUtils.isNullOrBlank(documnetNumber)){
            m= "请指定收货单号";
            return m;
        }
        if (StringUtils.isNullOrBlank(containNumber)){
            m= "请指定收货托盘码";
            return m;
        }
        if (StringUtils.isNullOrBlank(locationCode)){
            locationCode=XcmgAmConstants.LOCATION_CODE_PA0101;
        }
        documnetNumber=documnetNumber.trim();
        containNumber=containNumber.trim();
        if (actionDto==null){
            actionDto=new TaskActionDto();
        }
        if (StringUtils.isNullOrBlank(actionDto.getWorker())){
            actionDto.setWorker(SecurityUtils.getLoginUsername());
        }

        TwaDocAsnHeader header=null;
        List<TwaDocAsnDetails> linesall=null;
        List<TwaDocAsnDetails> lines=null;
        String batchnum=TextUtils.genBatchNumber();
        String lotnum=null;
        String deflotnum=DateUtils.format(new Date(), DateUtils.FORMAT_DATE_YYYYMMDD);
        BigDecimal qty=null;
        List<String> tracenums=new ArrayList<>();
        try{
            header=this.asnService.findByDocumentNumber(documnetNumber);
            if (header==null){
                m= "找不到指定的入库单.单号:"+documnetNumber;
                return m;
            }
            if (WmsConstants.ASN_STATUS_CLOSE.equalsIgnoreCase(header.getStatus())){
                m= "入库单已经关闭.单号:"+documnetNumber;
                return m;
            }
            if (WmsConstants.ASN_STATUS_CANCELL.equalsIgnoreCase(header.getStatus())){
                m= "入库单已经取消.单号:"+documnetNumber;
                return m;
            }
            if (WmsConstants.ASN_STATUS_RECEIVE.equalsIgnoreCase(header.getStatus())){
                m= "入库单已经完全收货.单号:"+documnetNumber;
                return m;
            }
            linesall=this.asnDetailsService.findByDocumentId(header.getId());
            if ((linesall==null) || (linesall.size()==0)){
                m= "找不到入库单明细行.单号:"+documnetNumber;
                return m;
            }
            for (TwaDocAsnDetails line:linesall){
                if (line==null){
                    continue;
                }
                if (WmsConstants.ASN_STATUS_CLOSE.equalsIgnoreCase(line.getLineStatus())){
                    continue;
                }
                if (WmsConstants.ASN_STATUS_CANCELL.equalsIgnoreCase(line.getLineStatus())){
                    continue;
                }
                if (WmsConstants.ASN_STATUS_RECEIVE.equalsIgnoreCase(line.getLineStatus())){
                    continue;
                }
                if ((line.getQtyReceived()!=null) && (line.getQtyReceived().compareTo(line.getQtyOrdered())>=0)){
                    continue;
                }
                lotnum=line.getLotattr05();
                if (StringUtils.isNullOrBlank(lotnum)){
                    lotnum=deflotnum;
                }
                line.setLotattr05(lotnum);
                qty=line.getQtyOrdered();
                if ((line.getQtyReceived()!=null)&&(line.getQtyReceived().compareTo(BigDecimal.ZERO)>0)){
                    qty=qty.subtract(line.getQtyReceived());
                }

                line.setContainNumber(containNumber);
                if ((!StringUtils.isNullOrBlank(line.getTraceNumber()))
                        && (!CodesConstants.COMMON_WILDCARD.equalsIgnoreCase(line.getTraceNumber()))){
                    if (!tracenums.contains(line.getTraceNumber().trim())){
                        tracenums.add(line.getTraceNumber().trim());
                    }
                }

                if ((StringUtils.isNullOrBlank(line.getTraceNumber()))
                        || (CodesConstants.COMMON_WILDCARD.equalsIgnoreCase(line.getTraceNumber()))){
                    line.setTraceNumber(line.getContainNumber());
                }

                //TODO:HU/202504
                /**
                m = this.receiveLine(batchnum, header, line, qty, lotnum, locationCode, line.getContainNumber(), line.getTraceNumber(),
                        actionDto.getWorkMode(), actionDto.getWorker());
                 **/
                if (!StringUtils.isNullOrBlank(m)){
                    return m;
                }
            }
            //
            if ((tracenums!=null) && (tracenums.size()>0)){
                this.inventorySeqService.updateContainNumberByTraceNumber(tracenums, containNumber, SecurityUtils.getLoginUsername());
            }
        }catch (Exception e){
            m="收货异常.错误:"+e.getMessage();
            e.printStackTrace();
        }
        return m;
    }

    //
    private String receiveAction(String batchNumber, TwmBasMaterial material, BigDecimal quantity, String uomCode, String lotNumber,
                               String containNumber, String traceNumber, String locationCode,
                               String documentNumber, String docLineNumber,
                               String productDate, String expireDate,
                               String workMode){
        String m = "";
        if (material==null){
            m="material is null";
            return m;
        }
        TwmBasCustomer customer=null;
        if (customer!=null){
            customer = this.customerService.lookup(material.getCustomerId());
        }

        ReceiveLineDto lineDto=new ReceiveLineDto();
        ReceiveActionDto actionDto=new ReceiveActionDto();

        lineDto.setDocumentNumber(this.trim(documentNumber));
        lineDto.setDocumetLineNumber(this.trim(docLineNumber));
        lineDto.setCustomerCode(null);
        if (customer!=null){
            lineDto.setCustomerCode(customer.getCode());
        }
        lineDto.setMaterialCode(material.getCode());
        lineDto.setLotNumber(this.trim(lotNumber));
        lineDto.setQuantity(quantity);
        lineDto.setUomCode(CodesConstants.UOM_EACH);

        lineDto.setRefMaterialId(null);
        if (material!=null){
            lineDto.setRefMaterialId(material.getId());
        }

        if (StringUtils.isNullOrBlank(containNumber)){
            containNumber=CodesConstants.COMMON_WILDCARD;
        }
        if ((StringUtils.isNullOrBlank(traceNumber))
                || (CodesConstants.COMMON_WILDCARD.equalsIgnoreCase(traceNumber))){
            if (!StringUtils.isNullOrBlank(containNumber)){
                traceNumber=containNumber;
            }
        }
        lineDto.setContainNumber(this.trim(containNumber));
        lineDto.setTraceNumber(this.trim(traceNumber));

        lineDto.setLocationCode(this.trim(locationCode));
        if (StringUtils.isNullOrBlank(lineDto.getLocationCode())){
            lineDto.setLocationCode(WmsConstants.LOCATION_DEF_RECEIVE_LOCATION);
        }
        lineDto.setQcStatus(WmsConstants.QUALITY_STATUS_PASS);
        if (StringUtils.isNullOrBlank(lineDto.getLotNumber())){
            lineDto.setLotNumber(DateUtils.format(new Date(),DateUtils.FORMAT_DATE_YYYYMMDD));
        }
        Date date=null;
        if (!StringUtils.isNullOrBlank(productDate)){
            date=DateUtils.tryParse(productDate.trim());
            if (date!=null){
                lineDto.setProductDate(DateUtils.format(date, DateUtils.FORMAT_DATE_YYYY_MM_DD_HH_MM_SS));
                lineDto.setUdf19(date);
            }
        }
        if (!StringUtils.isNullOrBlank(expireDate)){
            date=DateUtils.tryParse(expireDate.trim());
            if (date!=null){
                lineDto.setExpireDate(DateUtils.format(date, DateUtils.FORMAT_DATE_YYYY_MM_DD_HH_MM_SS));
            }
        }
        lineDto.setWorkTime(new Date());
        lineDto.setWorker(SecurityUtils.getLoginUsername());

        //
        m=this.working(containNumber, workMode);
        if (!StringUtils.isNullOrBlank(m)){
            return m;
        }

        //
        ReturnArrangeDataPack<ReturnArrangeDataItemDto> resultsitems=null;
        //
        try{
            m=createDocument(lineDto,actionDto);
        }catch (Exception e){
            m="单证校验出错:"+e.getMessage();
            e.printStackTrace();
        }
        if (!StringUtils.isNullOrBlank(m)){
            return m;
        }
        //
        try{
            actionDto.setBatchNumber(batchNumber);
            actionDto.setPalletizeMode(WmsConstants.RECEIVE_PALLETIZE_MODE_NONE);
            actionDto.setReceiveMode(WmsConstants.RECEIVE_MODE_NORMAL);
            if (!StringUtils.isNullOrBlank(workMode)){
                actionDto.setReceiveMode(workMode.trim());
            }
            actionDto.setAutoTaskAck(CodesConstants.COMMON_FLAG_NO);

            resultsitems=receiveService.receive(batchNumber, lineDto, actionDto, this.palletizeDataStorageBuilder);
            if (resultsitems==null){
                m="收货发生异常,请联系系统管理员";
            }else {
                m=this.errorMessage(resultsitems.getMessage());
            }
        }catch (Exception e){
            m="收货异常:"+e.getMessage();
            e.printStackTrace();
        }
        return m;
    }




// ---------------------------------------------------------------------------------------------
// ----  单证处理  -----------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------------

    private String createDocument(ReceiveLineDto receiveLine, ReceiveActionDto receiveAction){
        String m="";
        if (receiveLine==null){
            return m;
        }
        if (StringUtils.isNullOrBlank(receiveLine.getDocumentNumber())){
            return m;
        }
        Long clientid=this.clientConfig.globalClientid();
        Long customerid=this.clientConfig.customerid();
        Long divid=this.clientConfig.divisionid();

        TwaDocAsnHeader header=this.asnService.findByDocumentNumber(receiveLine.getDocumentNumber());
        if (header==null){
            header=new TwaDocAsnHeader();
            header.setGlobalClientId(clientid);
            header.setCustomerId(customerid);
            header.setDivisionId(divid);
            header.setDocumentNumber(receiveLine.getDocumentNumber().trim());
            header.setType(WmsConstants.ASN_TYPE_WORK_ORDER);
            header.setCreateSource(CodesConstants.SYSTEM_WMS);
            header.setEnabled(true);
            header.setEditable(true);
            header.setDelFlag(false);
            header.setCreatedBy(receiveLine.getWorker());
            header.setCreatedDate(new Date());
            header.setLastModifiedDate(header.getCreatedDate());
            header.setLastModifiedBy(header.getCreatedBy());
            try{
                this.asnService.save(header);
            }catch (Exception e){
                e.printStackTrace();
            }
        }
        TwaDocAsnDetails line = null;
        BigDecimal qtyopen=BigDecimal.ZERO;
        boolean increaseauto=false;
        List<TwaDocAsnDetails> lines=this.asnDetailsService.findByMaterial(header.getId(),receiveLine.getMaterialCode().trim());
        if ((lines!=null) && (lines.size()>0)){
            for (TwaDocAsnDetails da:lines){
                if (da==null){
                    continue;
                }
                if (WmsConstants.ASN_STATUS_CLOSE.equalsIgnoreCase(da.getLineStatus())){
                    continue;
                }
                if (WmsConstants.ASN_STATUS_CANCELL.equalsIgnoreCase(da.getLineStatus())){
                    continue;
                }
                if (WmsConstants.ASN_STATUS_RECEIVE.equalsIgnoreCase(da.getLineStatus())){
                    continue;
                }
                if (da.getQtyOrdered()==null){
                    continue;
                }
                qtyopen=BigDecimal.ZERO;
                if (da.getQtyReceived()!=null){
                    qtyopen=da.getQtyReceived();
                }
                if (receiveLine.getQuantity()!=null){
                    qtyopen=qtyopen.add(receiveLine.getQuantity());
                }
                if (da.getQtyOrdered().compareTo(qtyopen)>=0){
                    line=da;
                    break;
                }
                if (!CodesConstants.SYSTEM_WMS.equalsIgnoreCase(header.getType())) {
                    continue;
                }
                line=da;
                line.setQtyOrdered(qtyopen);
                line.setQtyOrderedEach(line.getQtyOrdered());
                if (StringUtils.isNullOrBlank(receiveLine.getLotNumber())) {
                    if (StringUtils.isNullOrBlank(da.getLotattr05())) {
                        line.setLotattr05(receiveLine.getLotNumber().trim());
                    }
                }
                line.setLastModifiedBy(receiveAction.getWorker());
                line.setLastModifiedDate(new Date());
                this.asnDetailsService.save(line);
                break;
            }
        }
        TwmBasMaterial material=null;
        if (line==null){
            material=materialService.findByCode(header.getCustomerId(),receiveLine.getMaterialCode().trim());
            if (material==null){
                m="找不到物料主数据.";
                return m;
            }
            line=new TwaDocAsnDetails();
            line.setHeaderId(header.getId());
            line.setLineNumber(this.asnDetailsService.nextLineNumber(header.getId()));
            line.setMaterialId(material.getId());
            line.setQtyOrdered(receiveLine.getQuantity());
            line.setQtyOrderedEach(line.getQtyOrdered());
            line.setQtyPalletized(BigDecimal.ZERO);
            line.setQtyPalletizedEach(line.getQtyPalletized());
            line.setQtyReceived(BigDecimal.ZERO);
            line.setQtyReceivedEach(line.getQtyReceived());
            if (receiveLine.getLotNumber()!=null){
                line.setLotattr05(receiveLine.getLotNumber().trim());
            }
            if (receiveLine.getQcStatus()!=null){
            }
            line.setLineStatus(WmsConstants.ASN_STATUS_CREATE);
            if (receiveLine.getRefMaterialId()==null){
                receiveLine.setRefMaterialId(material.getId());
            }
            line.setOverReceiveFlag(CodesConstants.COMMON_FLAG_YES);
            line.setCreatedBy(header.getCreatedBy());
            line.setCreatedDate(header.getCreatedDate());
            line.setLastModifiedDate(line.getCreatedDate());
            line.setLastModifiedBy(line.getCreatedBy());
            try{
                this.asnDetailsService.save(line);
                //this.asnDetailsService.flush();
            }catch (Exception e){
                e.printStackTrace();
            }
            if (StringUtils.isNullOrBlank(receiveLine.getDocumetLineNumber())){
                receiveLine.setDocumetLineNumber(line.getLineNumber());
            }
        }
        return m;
    }


// ---------------------------------------------------------------------------------------------
// ----  任务相关  ------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------------

    private String working(String containnumber, String workMode){
        String m="";
        if (containnumber==null){
            return m;
        }
        if (CodesConstants.COMMON_WILDCARD.equalsIgnoreCase(containnumber)) {
            return m;
        }
        try{
            List<TwtActTaskList> tasks=this.taskService.queryWorkingTasks("", "", "", containnumber,"","");
            if ((tasks==null)||(tasks.size()==0)){
                return m;
            }
            for (TwtActTaskList t:tasks){
                if (t==null){
                    continue;
                }
                if (CodesConstants.COMMON_STATUS_CLOSED.equalsIgnoreCase(t.getStatus())){
                    continue;
                }
                if (CodesConstants.COMMON_STATUS_CANCELLED.equalsIgnoreCase(t.getStatus())){
                    continue;
                }
                if ((workMode==null) || (!workMode.contains(WmsConstants.RECEIVE_MODE_MILK_RUN))){
                   if (!WmsConstants.TASK_STATUS_CREATE.equalsIgnoreCase(t.getStatus())) {
                       m = "托盘已经开始作业.托盘码:" + containnumber;
                       break;
                   }
                }
            }
        }catch (Exception e){
            m="校验任务异常:"+e.getMessage();
            e.printStackTrace();
        }
        return m;
    }

// ---------------------------------------------------------------------------------------------
// ----  拣货/发货  -----------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------------
    //
    public void populate(ShipHeaderDto header, List<ShipLineDto> lines, List<TwtActAllocationList> details){
        if ((details==null) || (details.size()==0)){
            header.setQtysum("0/0");
            return;
        }
        int count=0;
        BigDecimal sum=BigDecimal.ZERO;
        ShipLineDto line=null;
        Map<Long,TwmBasMaterial> materials=new HashMap<Long,TwmBasMaterial>();
        Map<Long,TwaDocSoHeader> soheaders=new HashMap<Long,TwaDocSoHeader>();
        TwaDocSoHeader soheader=null;
        for(TwtActAllocationList d:details){
            if (!check(d)){
                continue;
            }
            soheader=soheaders.get(d.getDocId());
            if (soheader==null){
                soheader=this.soService.findById(d.getDocId());
                if (soheader!=null){
                    soheaders.put(soheader.getId(),soheader);
                    header.setConsigneecode(soheader.getConsigneeCode());
                    header.setConsigneename(soheader.getConsigneeName());
                    header.setPlantoplace(soheader.getPlanLoadPlace());
                }
            }
            line=translateTo(d,materials,soheaders);
            if (line!=null){
                lines.add(line);
                count++;
                sum= MathUtils.add(sum, d.getQtyEach());
            }
            if(count==1){
                header.setCreateby(d.getCreatedBy());
                header.setCreatetime(DateUtils.format(d.getCreatedDate(),DateUtils.FORMAT_DATE_YYYY_MM_DD_HH_MM_SS));
                header.setContainnumber(d.getFromContainNumber());
            }
        }
        String qtysum=String.valueOf(count)+"/"+MathUtils.getQuantityString(sum);
        header.setQtysum(qtysum);

        this.calculatePickFullFlag(header.getContainnumber(), lines);
    }


    //默认
    public String shipment(String palletnumber,  String plantocontainnumber, String allocationid,
                           String documentnumber,  String plantoplace,
                           String shiptype, String shipmode,  String usercode){

        String m = "";

        if (StringUtils.isNullOrBlank(shiptype)){
            shiptype=WmsConstants.SHIP_ACTION_TYPE_CONTAIN;
        }
        if (WmsConstants.SHIP_ACTION_TYPE_ALLOCATION.equalsIgnoreCase(shiptype)){
            if (StringUtils.isNullOrBlank(allocationid)){
                m = "必须指定拣货ID.";
                return m;
            }
        }
        if (WmsConstants.SHIP_ACTION_TYPE_CONTAIN.equalsIgnoreCase(shiptype)){
            if (StringUtils.isNullOrBlank(palletnumber)){
                m = "必须指定托盘码.";
                return m;
            }
        }
        if (StringUtils.isNullOrBlank(plantocontainnumber)){
            if (!StringUtils.isNullOrBlank(palletnumber)){
                palletnumber=palletnumber.trim();
                plantocontainnumber=palletnumber+CodesConstants.COMMON_WILDCARD;
            }else {
                plantocontainnumber=CodesConstants.COMMON_WILDCARD;
            }
        }
        plantocontainnumber=plantocontainnumber.trim();

        m=checkPickDropoff(plantocontainnumber);
        if (!StringUtils.isNullOrBlank(m)){
            return m;
        }
        //
        String batchNumber= TextUtils.genBatchNumber();
        List<TwtActAllocationList> allocations=new ArrayList<>();
        TwtActAllocationList allocation=null;
        TwaDocSoHeader header=null;
        List<TwaInventoryDetails> storages=null;
        HashMultimap<Long, String> sotraces=HashMultimap.create();
        HashMultimap<Long, TwtActAllocationList> soallocations=HashMultimap.create();
        Set<TwtActAllocationList> soallocation=null;
        AllocationActionDto actionDto=new AllocationActionDto();
        Map<Long, TwaDocSoHeader> headers=new HashMap<>();
        Set<String> tracenums=new HashSet<>();
        try{
            //
            if (shiptype.equals(WmsConstants.SHIP_ACTION_TYPE_ALLOCATION)){
                if (StringUtils.isNullOrBlank(allocationid)){
                    m = "请选中拣货行号";
                    return m;
                }
                allocation=this.allocationService.findById(Long.valueOf(allocationid));
                if (allocation==null){
                    m = "找不到拣货单,请确认是否已删除,拣货ID:"+String.valueOf(allocationid);
                    return m;
                }
                if (WmsConstants.SO_STATUS_SHIP.compareToIgnoreCase(allocation.getStatus())<=0){
                    m = "已经发货,不能重复执行.拣货ID:"+String.valueOf(allocationid);
                }
                allocations.add(allocation);
                header=this.soService.findById(allocation.getDocId());
                headers.put(allocation.getDocId(), header);
            }
            //
            if (shiptype.equals(WmsConstants.SHIP_ACTION_TYPE_CONTAIN)){
                if (StringUtils.isNullOrBlank(palletnumber)){
                    m =  "请指定托盘码";
                    return m;
                }
                allocations=this.allocationService.queryReadyShippment(palletnumber.trim());
            }

            //目标托盘占有库存
            if (!StringUtils.isNullOrBlank(plantocontainnumber)){
                actionDto.setPlantoContainNumber(plantocontainnumber.trim());
                if ((!this.skipTracenumber(plantocontainnumber))
                        && (allocations.get(0).getFromContainNumber().equalsIgnoreCase(palletnumber))){
                    storages=this.inventoryService.findByContainNumber(plantocontainnumber);
                    if (storages!=null){
                        for (TwaInventoryDetails storage:storages){
                            if (storage==null){
                                continue;
                            }
                            if ((storage.getQtyAllocated()==null) || (storage.getQtyAllocated().compareTo(storage.getQty())<0)){
                                m = "发运失败.零拣发货,请指定有效的目标托盘码";
                            }
                        }
                    }
                }
            }

        }catch (Exception e){
            m="发货失败.异常:"+e.getMessage();
            e.printStackTrace();
        }
        if ((allocations==null)||(allocations.size()==0)){
            m =  "发运失败:找不到待发运作业";
            return m;
        }
        try{
            //变更目标箱码/托盘码
            if (!this.skipTracenumber(plantocontainnumber)){
                this.changePlantoContainnumber(allocations, plantocontainnumber);
            }
            //
            for (TwtActAllocationList a:allocations){
                if (a==null){
                    continue;
                }
                if (StringUtils.isNullOrBlank(a.getFromTraceNumber())){
                    continue;
                }
                soallocations.put(a.getDocId(), a);
                sotraces.put(a.getDocId(), a.getFromTraceNumber());
                header=headers.get(a.getDocId());
                if (header==null){
                    header=this.soService.findById(a.getDocId());
                    headers.put(a.getDocId(), header);
                }
                if (WmsConstants.SO_TYPE_WORK_ORDER.equalsIgnoreCase(header.getType())){
                    if (StringUtils.isNullOrBlank(plantocontainnumber)){
                        m =  "生产工单,必须扫描目标托盘(料箱码).";
                        return m;
                    }
                    if (this.skipTracenumber(plantocontainnumber)){
                        m =  "生产工单,必须扫描有效的目标托盘(料箱码).当前:"+plantocontainnumber;
                        return m;
                    }
                }
            }
            if ((soallocations==null) || (soallocations.size()==0)){
                return m;
            }

            for (Long docid:soallocations.keySet()){
                if (docid==null){
                    continue;
                }
                soallocation = soallocations.get(docid);
                if ((soallocation==null) || (soallocation.size()==0)){
                    return m;
                }
                header=headers.get(docid);
                //
                //发货
                actionDto.setPackAllocateMode(CodesConstants.COMMON_FLAG_NO);
                actionDto.setAutoTaskAck(CodesConstants.COMMON_FLAG_NO);

                if (!StringUtils.isNullOrBlank(plantocontainnumber)){
                    actionDto.setPlantoContainNumber(plantocontainnumber.trim());
                }
                if (!StringUtils.isNullOrBlank(plantoplace)){
                    actionDto.setPlantoPlaceCode(plantoplace.trim());
                }

                // 发运
                m = this.allocationService.shipment(batchNumber, header, new ArrayList<>(soallocation), actionDto);
                if (!StringUtils.isNullOrBlank(m)){
                    return m;
                }

                // 上传MES
                if (!CodesConstants.COMMON_WILDCARD.equalsIgnoreCase(plantocontainnumber)) {
                    /**
                    tracenums = sotraces.get(docid);
                    if ((tracenums==null) || (tracenums.size()==0)){
                        return m;
                    }
                     **/
                    tracenums.add(plantocontainnumber);

                    //TODO:HU/202504
                    //m = this.reportShipBingding(header, tracenums);

                    //alert record
                    if (!StringUtils.isNullOrBlank(m)) {
                        return m;
                    }
                }
            }
        }catch (Exception e){
            m="发货失败.异常:"+e.getMessage();
            e.printStackTrace();
        }
        return m;
    }

    //更新产品序列/发运
    public String sequenceShip(Long allocationId, String sequenceNumber, String documentNumber, String traceNumber, String containNumber,
                               String workMode, String worker){
        String m = "";

        if ((allocationId==null) || (allocationId<=0)){
            m = "请扫描有效的拣货数据.";
            return m;
        }
        if (StringUtils.isNullOrBlank(sequenceNumber)){
            m = "请扫描有效的产品序列.";
            return m;
        }
        if (StringUtils.isNullOrBlank(worker)){
            worker=SecurityUtils.getLoginUsername();
        }
        sequenceNumber=sequenceNumber.trim();

        TwtActAllocationList allocation=null;
        TwaDocSoHeader header=null;
        List<TwaInventoryStorageSeqList> seqs=null;
        TwaInventoryStorageSeqList seq=null;
        try{
            allocation=this.allocationService.findById(allocationId);
            if (allocation==null){
                m="找不到拣货数据,是否已经取消分配.ID:"+String.valueOf(allocationId);
                return m;
            }
            if (WmsConstants.SO_STATUS_CLOSE.equalsIgnoreCase(allocation.getStatus())){
                m="拣货已经完成,无法更新产品序列.ID:"+String.valueOf(allocationId);
                return m;
            }
            if (WmsConstants.SO_STATUS_CANCELL.equalsIgnoreCase(allocation.getStatus())){
                m="拣货已经取消,无法更新产品序列.ID:"+String.valueOf(allocationId);
                return m;
            }
            if (WmsConstants.SO_STATUS_SHIP.equalsIgnoreCase(allocation.getStatus())){
                m="拣货已经完成发运,无法更新产品序列.ID:"+String.valueOf(allocationId);
                return m;
            }
            if (StringUtils.isNullOrBlank(traceNumber)){
                traceNumber=allocation.getFromTraceNumber();
            }
            traceNumber=traceNumber.trim();

            /**
            seqs=this.inventorySeqService.findByTraceNumber(traceNumber);
            if ((seqs==null)||(seqs.size()==0)){
                m="找不到产品序列.箱码:"+traceNumber;
                return m;
            }
            **/
            seq=this.inventorySeqService.findBySeqNumber(sequenceNumber);
            if (seq==null){
                m="找不到产品序列.序列号:"+sequenceNumber;
                return m;
            }
            if (CodesConstants.COMMON_STATUS_CLOSED.equalsIgnoreCase(seq.getStatus())){
                m="产品序列已经关闭.序列号:"+sequenceNumber;
                return m;
            }
            if (!StringUtils.isNullOrBlank(seq.getShipDocNumber())){
                m="产品序列已经绑定发运单证.单证号:"+seq.getShipDocNumber();
                return m;
            }
            if (!traceNumber.equalsIgnoreCase(seq.getTraceNumber())){
                m="产品序列箱号与当前箱号不一致.序列号:"+sequenceNumber+"产品序列箱号:"+seq.getTraceNumber()+",当前箱号:"+traceNumber;
                return m;
            }
            if (StringUtils.isNullOrBlank(documentNumber)){
                header=this.soService.findById(allocation.getDocId());
                if (header==null){
                    m="找不到发运订单,请确认是否已删除.单证ID:"+String.valueOf(allocation.getDocId());
                    return m;
                }
                documentNumber=header.getDocumentNumber();
            }
            documentNumber=documentNumber.trim();
            seq.setShipDocNumber(documentNumber);
            seq.setShipTransId(allocation.getId());
            if (WmsConstants.SO_STATUS_SHIP.compareTo(seq.getStatus())>0){
                seq.setStatus(WmsConstants.SO_STATUS_SHIP);
            }
            seq.setLastModifiedDate(new Date());
            seq.setLastModifiedBy(worker);

            this.inventorySeqService.save(seq);
        }catch (Exception e){
            m="更新产品序列失败.异常:"+e.getMessage();
            e.printStackTrace();
        }
        return m;
    }

    /** TODO:HU/202504
    public String reportShipBingding(TwaDocSoHeader header, Set<String> delivertContainnumbers){
        String m = "";
        if (header==null){
            return m;
        }
        if (StringUtils.isNullOrBlank(header.getRefDocNumber())){
            return m;
        }
        if ((delivertContainnumbers==null)||(delivertContainnumbers.size()==0)){
            return m;
        }
        ShipTransBindingData reportData=null;
        RuiliResultData resultdata=null;
        try{
            reportData= RuiliMesExchangeSupport.transToMaterialRequisitionBinding(header, delivertContainnumbers);
            if (reportData!=null){
                resultdata = materialRequisitionBindingServiceProxy.report(Arrays.asList(reportData));
                m=RuiliMesExchangeSupport.textValueOf(resultdata);
            }
        }catch (Exception e){
            m="发送接口失败.异常:"+e.getMessage();
            e.printStackTrace();
        }
        return m;
    }
    **/

    private boolean check(TwtActAllocationList details){
        if (details==null){
            return false;
        }
        if (!StringUtils.isNullOrBlank(details.getStatus())){
            if (details.getStatus().compareTo(WmsConstants.SO_STATUS_SHIP)>=0){
                return false;
            }
        }
        if (StringUtils.isNullOrBlank(details.getFromTraceNumber())){
            return false;
        }
        if (!MathUtils.validQuantity(details.getQtyEach())){
            return false;
        }
        return true;
    }

    private ShipLineDto translateTo(TwtActAllocationList details, Map<Long, TwmBasMaterial> materials, Map<Long, TwaDocSoHeader> headers){
        ShipLineDto data=new ShipLineDto();

        data.setId(String.valueOf(details.getId()));
        data.setTransactionid(String.valueOf(details.getId()));
        data.setVersion(details.getVersion());
        data.setLinesequence(details.getDocLinenumber());
        TwmBasMaterial mat=materials.get(details.getMaterialId());
        if (mat==null){
            mat=materialService.findById(details.getMaterialId());
            if (mat==null){
                return null;
            }
            materials.put(details.getMaterialId(), mat);
        }
        if (mat!=null){
            data.setMaterialcode(mat.getCode());
            data.setMaterialname(mat.getName());
        }
        data.setQuantity(details.getQty());
        data.setQuantityeach(details.getQtyEach());
        //
        data.setUom(details.getUomCode());
        data.setWorking(CodesConstants.DATA_WORKING_QUERY);
        data.setWorkmode("");
        data.setDocumentnumber(details.getDocNumber());
        data.setDocumentlinenumber(details.getDocLinenumber());
        data.setLotnumber(details.getLotNumber());
        data.setTracenumber(details.getFromTraceNumber());
        data.setContainnumber(details.getFromContainNumber());
        data.setFromlocationcode(this.locationResolver.check(details.getFromLocId()));
        data.setQuantity(details.getQty());
        data.setQuantityeach(details.getQtyEach());
        data.setTotracenumber(details.getToTraceNumber());
        data.setTocontainnumber(details.getToContainNumber());
        data.setTolocationcode(this.locationResolver.check(details.getToLocId()));
        if ((StringUtils.isNullOrBlank(data.getTolocationcode()))
                && (details.getPlantoLocId()!=null)){
            data.setTolocationcode(this.locationResolver.check(details.getPlantoLocId()));
        }

        TwaDocSoHeader header=headers.get(details.getDocId());
        if (header!=null){
            data.setPlantoplace(header.getPlanLoadPlace());
        }
        data.setLinestatus(details.getStatus());
        data.setLinestatusname(this.getCodeName(WmsConstants.CODE_TYPE_SO_STATUS, details.getStatus()));
        data.setCreatetime(DateUtils.format(details.getCreatedDate(),DateUtils.FORMAT_DATE_YYYY_MM_DD_HH_MM_SS));
        data.setCreateby(details.getCreatedBy());
        return data;
    }

    public String calculatePickFullFlag(String containnum, List<ShipLineDto> lines){
        String m = "";
        if (lines==null){
            return m;
        }

        List<TwaInventoryDetails> storages=null;
        Map<String, BigDecimal> tracestorageqty=new HashMap<>();
        Map<String, BigDecimal> tracepickqty=new HashMap<>();
        Map<String, List<PickTaskHeaderDto>> traceline=new HashMap<>();
        Map<String, String> traceflags=new HashMap<>();
        String flag="";

        try{
            storages=this.inventoryService.findByContainNumber(containnum.trim());
            if ((storages==null)||(storages.size()==0)){
                return m;
            }
            for (TwaInventoryDetails sd:storages){
                if (sd==null){
                    continue;
                }
                flag=CodesConstants.COMMON_FLAG_YES;
                flag=traceflags.get(sd.getTraceNumber());
                if (flag==null){
                    flag=CodesConstants.COMMON_FLAG_YES;
                    traceflags.put(sd.getTraceNumber(),flag);
                }
                if (flag.equalsIgnoreCase(CodesConstants.COMMON_FLAG_NO)){
                    continue;
                }
                if ((sd.getQtyAllocated()==null) || (sd.getQtyAllocated().compareTo(sd.getQty())<0)){
                    flag=CodesConstants.COMMON_FLAG_NO;
                    traceflags.put(sd.getTraceNumber(),flag);
                }
            }
        }catch (Exception e){
            m="error/"+e.getMessage();
            e.printStackTrace();
        }
        for (ShipLineDto line:lines){
            if (line==null){
                continue;
            }
            flag=CodesConstants.COMMON_FLAG_YES;
            flag=traceflags.get(line.getTracenumber());
            line.setFullflag(flag);
        }
        return m;
    }


    public String getCodeName(String typeCode, String code){
        String name="";
        if ((StringUtils.isNullOrBlank(typeCode)) || (StringUtils.isNullOrBlank(code))){
            return name;
        }
        name=codeListService.textByValue(typeCode,code);
        return name;
    }


// ---------------------------------------------------------------------------------------------
// --------  盘点    ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------------
    public List<TwtActTaskList> queryCountTask(String documentnumber, String zonecode, String locationcode, String containnumber,
                                               String tracenumber,  String releasestatus,  String lasttasknumber,  String usercode, Pageable page){
        List<TwtActTaskList> tasks=null;
        Page<TwtActTaskList> ptasks=null;
        Long zoneid=null;
        LocationLineDto loc=null;
        Map<String, Object> params=new HashedMap();
        if (!StringUtils.isNullOrBlank(documentnumber)){
            params.put("docNumber", documentnumber.trim());
        }
        if (!StringUtils.isNullOrBlank(zonecode)){
            zoneid=this.zoneService.retrieve(zonecode.trim());
            if (zoneid==null){
                return tasks;
            }
            params.put("fromLocation.zoneId", zoneid);
        }
        if (!StringUtils.isNullOrBlank(locationcode)){
            loc=this.locationResolver.lookup(locationcode.trim());
            if (loc==null){
                return tasks;
            }
            params.put("fromLocId", loc.getLocationId());
        }
        if (!StringUtils.isNullOrBlank(containnumber)){
            params.put("fromContainNumber", containnumber.trim());
        }
        if (!StringUtils.isNullOrBlank(tracenumber)){
            params.put("fromTraceNumber", tracenumber.trim());
        }
        if (!StringUtils.isNullOrBlank(releasestatus)){
            params.put("releaseStatus", releasestatus.trim());
        }
        if (page==null){
            page = PageRequest.of(0, 50, Sort.by("fromLocation.pkSeqCode", "fromContainNumber", "fromTraceNumber"));
        }
        List<TwtActTaskList> orderedtasks=null;
        List<TwtActTaskList> lasttasks=null;
        TwtActTaskList lasttask=null;
        LocationLineDto lastloc=null;
        int index=-1;
        int pos=0;
        int match=0;
        try{
            ptasks = this.taskService.findAll(params, page);
            if ((ptasks==null) || (ptasks.getContent()==null) || (ptasks.getContent().size()==0)){
                return tasks;
            }
            tasks = ptasks.getContent();
            if (!StringUtils.isNullOrBlank(lasttasknumber)){
                lasttasks=this.taskService.findByNumber(lasttasknumber.trim());
                if ((lasttasks!=null)&&(lasttasks.size()>0)){
                    lasttask=lasttasks.get(0);
                }
            }
            if (lasttask!=null){
                lastloc=this.locationResolver.lookup(lasttask.getFromLocId());
                for (TwtActTaskList t:tasks){
                    index++;
                    if (t.getFromTraceNumber().equalsIgnoreCase(lasttask.getFromTraceNumber())){
                        match=5;
                        pos=index;
                        break;
                    }
                    if (t.getFromTraceNumber().equalsIgnoreCase(lasttask.getFromTraceNumber())){
                        if (match<=4){
                            pos=index;
                            match=4;
                        }
                    }
                    loc=this.locationResolver.lookup(t.getFromLocId());
                    if (loc.getLocationId().equals(lastloc.getLocationId())){
                        if (match<=3){
                            pos=index;
                            match=3;
                        }
                    }
                    if (loc.getZoneId().equals(lastloc.getZoneId())){
                        if (match<=2){
                            pos=index;
                            match=2;
                        }
                    }
                }
            }
            if (pos>0){
                orderedtasks=new ArrayList<>();
                orderedtasks.addAll(tasks.subList(pos, tasks.size()));
                orderedtasks.addAll(tasks.subList(0, pos));
                tasks=orderedtasks;
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return tasks;
    }




    //更新分配/任务为新的目标箱码
    //MES接口使用
    private String changePlantoContainnumber(List<TwtActAllocationList> allocations, String plantocontainnumber){
        String m = "";
        if ((allocations==null)||(allocations.size()==0)){
            return m;
        }
        if (StringUtils.isNullOrBlank(plantocontainnumber)){
            plantocontainnumber=CodesConstants.COMMON_WILDCARD;
        }
        plantocontainnumber=plantocontainnumber.trim();

        List<TwtActTaskList> tasks=null;
        boolean change=false;
        try{
            for (TwtActAllocationList a:allocations){
                change=false;
                //默认
                if ((a.getToContainNumber().endsWith(CodesConstants.COMMON_WILDCARD))
                        && (!plantocontainnumber.equalsIgnoreCase(a.getToTraceNumber()))){
                    a.setToContainNumber(plantocontainnumber);
                    a.setToTraceNumber(a.getToContainNumber());
                    a.setPlantoContainNumber(a.getToContainNumber());
                    a.setPlantoTraceNumber(a.getToTraceNumber());
                    this.allocationService.save(a);
                    change=true;
                }
                if (!change){
                    continue;
                }
                tasks=this.taskService.refPickTask(a.getId());
                if ((tasks==null) || (tasks.size()==0)){
                    continue;
                }
                for (TwtActTaskList t:tasks){
                    if (t==null){
                        continue;
                    }
                    if (!WmsConstants.TASK_TYPE_PICK.equalsIgnoreCase(t.getType())){
                        continue;
                    }
                    if (WmsConstants.TASK_STATUS_CLOSE.equalsIgnoreCase(t.getStatus())){
                        continue;
                    }
                    if (WmsConstants.TASK_STATUS_CANCEL.equalsIgnoreCase(t.getStatus())){
                        continue;
                    }
                    t.setToContainNumber(plantocontainnumber);
                    t.setToTraceNumber(a.getToContainNumber());
                    t.setPlantoContainNumber(a.getToContainNumber());
                    t.setPlantoTraceNumber(a.getToTraceNumber());
                    this.taskService.save(t);
                }
            }
        }catch (Exception e){
            m="更新分配数据目标跟踪号失败.异常:"+e.getMessage();
            e.printStackTrace();
        }
        return m;
    }

    private boolean skipTracenumber(String tracenum){
        if (StringUtils.isNullOrBlank(tracenum)){
            return true;
        }
        if (tracenum.equalsIgnoreCase(CodesConstants.COMMON_WILDCARD)){
            return true;
        }
        if (tracenum.endsWith(CodesConstants.COMMON_WILDCARD)){
            return true;
        }
        if (tracenum.startsWith(CodesConstants.COMMON_WILDCARD)){
            return true;
        }

        return false;
    }

    private String checkPickDropoff(String plantoTrcenumber){
        String m="";
        if (this.skipTracenumber(plantoTrcenumber)){
            return m;
        }
        List<TwaInventoryDetails> storages=null;
        try{
            storages=this.inventoryService.findByContainNumber(plantoTrcenumber);
            if ((storages==null)||(storages.size()==0)){
                return m;
            }
            m="发货失败,目标托盘码绑定有库存.托盘码:"+plantoTrcenumber+",库位:"+storages.get(0).getLocCode();
        }catch (Exception e){
            e.printStackTrace();
        }
        return m;
    }



// ---------------------------------------------------------------------------------------------
// ----  站台作业  ------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------------


// ---------------------------------------------------------------------------------------------
// ----  通用功能  ------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------------


// ---------------------------------------------------------------------------------------------
// ----  通用功能  ------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------------
    private String trim(String text){
        if (text==null){
            return "";
        }
        return text.trim();
    }

    private String errorMessage(ReturnMessageInfoData msgInfoData){
        String m="";
        if (msgInfoData==null){
            return m;
        }
        if (!CodesConstants.COMMON_FLAG_NO.equalsIgnoreCase(msgInfoData.getRetvalue())){
            return m;
        }
        m=msgInfoData.getRetcontent();
        if (com.pi.framework.core.util.StringUtils.isNullOrBlank(m)){
            m=msgInfoData.getRetcode();
        }
        if (com.pi.framework.core.util.StringUtils.isNullOrBlank(m)){
            m="操作发生异常,请联系系统管理员";
        }
        return m;
    }

// ---------------------------------------------------------------------------------------------
// ----  导入/单证  -----------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------------
   public String syncDocumentDataToStorage(TwaDocAsnHeader header, TwaDocAsnDetails line, TwaInventoryDetails storage){
        String m = "";
        if (header==null){
            return m;
        }
        if (storage==null){
            return m;
        }
        if ((!StringUtils.isNullOrBlank(header.getHEdi02()))
               && (StringUtils.isNullOrBlank(storage.getReserveCode()))){
           storage.setReserveCode(header.getHEdi02().trim());
        }
        //HEdi05:change line
        //
        if (!StringUtils.isNullOrBlank(header.getRefSoNumber())){
            storage.setReserveDocNumber(header.getRefSoNumber().trim());
        }

        if ((!StringUtils.isNullOrBlank(header.getSupplierCode()))
               && (StringUtils.isNullOrBlank(storage.getUdf11()))){
           storage.setUdf11(header.getSupplierCode().trim());
        }
        if (line!=null){
            if ((!StringUtils.isNullOrBlank(line.getDEdi04()))
                    && (StringUtils.isNullOrBlank(storage.getReserveCode()))){
                storage.setReserveCode(line.getDEdi04().trim());
            }
            if ((!StringUtils.isNullOrBlank(line.getDEdi05()))
                    && (StringUtils.isNullOrBlank(storage.getUdf11()))){
                storage.setUdf11(line.getDEdi05().trim());
            }
        }
        return m;
   }

// ---------------------------------------------------------------------------------------------
// -----  内部方法  -----------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------------


}
